#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <pthread.h>

#define NUMPTHREAD 10
#define NUMCOLA 15
#define PORT 8080
#define MAXBUFFER 1024
#define FILES "files/"

#define PNG "image/png"
#define JPG "image/jpeg"
#define GIF "image/gif"
#define HTM "text/html"
#define TXT "text/plain"

typedef struct {
	int cola[NUMCOLA];
	int tEspera[NUMPTHREAD];
	int numElementos;
	int peticiones;
} WebServer;

char* getContentType(char* extension) {
	if (strcmp(extension, ".html") == 0)
		return HTM;
	else if (strcmp(extension, ".htm") == 0)
		return HTM;
	else if (strcmp(extension, ".png") == 0)
		return PNG;
	else if (strcmp(extension, ".gif") == 0)
		return GIF;
	else if (strcmp(extension, ".jpeg") == 0)
		return JPG;
	else
		return TXT;

}

void responseHTTP(int fd, int busy) {

	if (busy == 1) {
		char* body = "<html><title>Server Busy!!</title><p>Server Busy!!</html>";
		char* baseError = "HTTP/1.0 404 File not found\nContent-Type: text/html\nContent-Length: %d\n\n%s";
		char* response = malloc(strlen(baseError) + strlen(body) + 1);
		sprintf(response, baseError, strlen(body), body);
		send(fd, response, strlen(response), 0);
		free(response);
		return;
	}

	int n = 0;
	char buffer[MAXBUFFER];
	char *extension = malloc(5);
	char *status = malloc(18);
	char *contentType = malloc(11);
	char *fileName;
	char *space = " ";
	int count = 0;

	bzero(buffer, MAXBUFFER);
	n = read(fd, buffer, MAXBUFFER);
	if (n < 0)
		error("ERROR reading from socket");

	fileName = strtok(buffer, space);
	fileName = strtok(NULL, space);
	char* baseHttp = "HTTP/1.0 %s\r\nContent-Type: %s\r\n\r\n";

	bzero(buffer, strlen(buffer));
	char *ext = strrchr(fileName, '.');
	bzero(buffer, strlen(buffer));

	int ok = 0;
	if (ext != NULL) {
		char *fullName = malloc(strlen(fileName) + strlen(FILES) + 1);
		sprintf(fullName, "files%s", fileName);
		FILE *f = fopen(fullName, "rb");
		if (f != NULL) {

			ok = 1;
			status = "200 OK";
			extension = ext;
			contentType = getContentType(ext);

			fseek(f, 0, SEEK_END);
			int fileLen = ftell(f);
			fseek(f, 0, SEEK_SET);

			char* response = malloc(strlen(baseHttp) + strlen(status) + strlen(contentType) + 1);
			sprintf(response, baseHttp, status, contentType);
			send(fd, response, strlen(response), 0);
			free(response);

			while (!feof(f)) {
				count = fread(buffer, 1, MAXBUFFER, f);
				send(fd, buffer, count, 0);
			}
			fclose(f);
		}
	}

	if (ok != 1) {
		char* body = "<html><title>Error 404 (Not Found)!!</title><p>The requested URL was not found on this server.</html>";
		char* baseError = "HTTP/1.0 404 File not found\nContent-Type: text/html\nContent-Length: %d\n\n%s";
		char* response = malloc(strlen(baseError) + strlen(body) + 1);
		sprintf(response, baseError, strlen(body), body);
		send(fd, response, strlen(response), 0);
		free(response);
	}
	close(fd);
}

void initializeServer(WebServer *server) {
	int i = 0;
	for (i = 0; i < NUMCOLA; i++) {
		(*server).cola[i] = -1;
	}
	for (i = 0; i < NUMPTHREAD; i++) {
		(*server).tEspera[i] = generateRandomWait();
	}
	(*server).numElementos = 0;
	(*server).peticiones = 0;
}

void insertFD(WebServer *server, int fd) {
	int i = 0;
	for (i = 0; i < NUMCOLA; i++) {
		if ((*server).cola[i] == -1) {
			(*server).cola[i] = fd;
			return;
		}
	}
}

int getFD(WebServer *server) {
	int i = 0;
	int fd = -1;
	for (i = 0; i < NUMCOLA; i++) {
		if ((*server).cola[i] != -1) {
			fd = (*server).cola[i];
			(*server).cola[i] = -1;
			return fd;
		}
	}
	return fd;
}

void viewServer(WebServer server) {
	int i = 0;
	printf("[");
	for (i = 0; i < NUMCOLA; i++) {
		if (i == NUMCOLA - 1) {
			if (server.cola[i] == -1)
				printf("X]");
			else
				printf("%d]", server.cola[i]);
		} else {
			if (server.cola[i] == -1)
				printf("X\t");
			else
				printf("%d\t", server.cola[i]);
		}
	}
	printf("\t[%d]\n", server.peticiones);
}

void trace(WebServer server, int threadId, int fd) {
	if (threadId == -1)
		printf("Añadir: \t Valor: %d\t", fd);
	else
		printf("Thread: %d\t Valor: %d\t", threadId, fd);
}

int generateRandom(void) {
	return (rand() % 20);
}

int generateRandomWait(void) {
	return (rand() % 4) + 1;
}
